import {Order} from '../models/Order';
import {OrderStatus} from '../GameDef';
import Tools from '../tools/tools';
import {GenerateOrderRule} from '../rules/GenerateOrderRule';

/**
 * 牌库类 - 管理一组卡牌 (单例模式)
 */
export class OrderPoolMgr {
    /** 单例实例 */
    private static _instance: OrderPoolMgr | null = null;

     /** 牌库ID */
     private _uid: string;

     private _genRules: GenerateOrderRule;

     private _useOrderCnt: number = 0;

     private _orders: Order[] = [];
     private _sequence: string[] = [];

     /**
      * 获取牌库ID
      */
     get uid(): string {
         return this._uid;
     }

     get userOrderCnt(): number {
         return this._useOrderCnt; 
     }

    /**
     * 私有构造函数
     * @param uid 牌库ID
     * @param name 牌库名称
     * @param cards 初始卡牌列表
     */
    private constructor() {
        this._uid = '';
        this._orders = [];
        this._genRules = new GenerateOrderRule();
    }

    get isHaveNewOrder(): boolean {
        return this.userOrderCnt < this._sequence.length; 
    }

    get orders(): Order[] {
        return [...this._orders];
    }

    get size(): number {
        return this._orders.length;
    }

    get isEmpty(): boolean {
        return this._orders.length === 0;
    }

    /**
     * 获取牌库单例实例
     * @param name 牌库名称 (仅首次调用时有效)
     * @param cards 初始卡牌列表 (仅首次调用时有效)
     * @returns 牌库单例实例
     */
    public static getInstance(): OrderPoolMgr {
        if (!OrderPoolMgr._instance) {
            OrderPoolMgr._instance = new OrderPoolMgr();
        }
        return OrderPoolMgr._instance;
    }

    markOrderFinish(order: Order | number): void {
        if(order instanceof Order)
            order.status = OrderStatus.FINISH;
        else
            this.getOrderById(order).status = OrderStatus.FINISH;
    }

    /**
     * 重置单例实例
     * 在需要完全重新初始化牌库时使用
     */
    public static resetInstance(): void {
        OrderPoolMgr._instance = null;
    }

    addOrder(order:Order): void {
        this._orders.push(order);
    }


    addOrders(order: Order[]): void {
        this._orders.push(...order);
    }


    removeCard(order: Order): boolean {
        const index = this._orders.findIndex(o => o.uid === order.uid);
        if (index !== -1) {
            this._orders.splice(index, 1);
            return true;
        }
        return false;
    }

    /**
     * 根据条件从牌库中获取卡牌
     * @param condition 筛选条件
     * @returns 符合条件的卡牌列表
     */
    getCardsByCondition(condition: (card: Order) => boolean): Order[] {
        return this._orders.filter(condition);
    }

    /**
     * 根据ID获取卡牌
     * @param id 卡牌ID
     * @returns 找到的卡牌，如果不存在则返回undefined
     */
    getOrderById(id: number): Order | undefined {
        return this._orders.find(order => order.uid === id);
    }
    
    /**
     * 随机获取一张卡牌
     * @param condition 可选的筛选条件
     * @returns 随机卡牌，如果牌库为空则返回undefined
     */
    getRandomOrder(condition?: (order: Order) => boolean): Order | undefined {
        const availableCards = condition ? this._orders.filter(condition) : this._orders;
        if (availableCards.length === 0) {
            return undefined;
        }
        const randomIndex = Math.floor(Math.random() * availableCards.length);
        return availableCards[randomIndex];
    }

    getUnusedOrder(): Order | undefined {
        return this.getRandomOrder(order => order.status == OrderStatus.NONE);
    }

    getUsedOrder(): Order[] {
        let orders: Order[] = [];
        for(let order of this._orders){
            if(order.status == OrderStatus.USED)
                orders.push(order);
        }
        return orders;
    }

    get finishedOrdersCount(): number {
        let count = 0;
        for(let order of this._orders){
            if(order.status == OrderStatus.FINISH)
                count++;
        }
        return count;
    }

    get unFinishedOrdersCount(): number {
        let count = 0;
        for(let order of this._orders){
            if(order.status != OrderStatus.FINISH)
                count++;
        }
        return count;
    }


    /**
     * 重置牌库中所有卡牌的状态
     */
    reset(): void {
        
    }

    /**
     * 清空牌库中的所有卡牌
     */
    clear(): void {
        this._uid = '';
        this._useOrderCnt = 0;
        this._orders = [];
        this._sequence = [];
    }

    /**
     * 加载新的卡牌集合到牌库中
     * 用于在切换关卡时更换新的牌库
     * @param cards 要加载的卡牌列表
     */
    async load(filename: string): Promise<void> {
        // 清空当前牌库
        this.clear();

        let cfg = await Tools.loadJson(`maps/${filename}`);
        let orderCfg = cfg.orders;
        if (!orderCfg)
            return console.log("load failed! orderCfg is null!");

        this._uid = filename;
        for (let i = 0; i < orderCfg.length; i++) {
            let o = orderCfg[i];
            let order = new Order(o.uid, o.values, o.suitCheck, o.name);

            let rule = cfg.sequence[i];
            if (!rule)
                return console.log("load failed! rule is null!");

            if(rule){
                this.addOrder(order);
                this._sequence.push(rule);
            }
            
        }
    }

    getNextOrder(): Order | undefined {
       if(this.userOrderCnt >= this._sequence.length)
            return undefined;
        
        const origin = this._sequence[this.userOrderCnt];
        let ruleName = origin;
        let agList = ruleName.split('_');
        let params = [];
        if (agList.length > 1) {
            ruleName = agList[0];
            params = agList.slice(1)
        }
        
        let func = this._genRules[ruleName];
        if (!func) {
            console.log(`ruleName [${func}] is not exist!`)
            return;
        }

        let orders = func.call(this._genRules, this, ...params);
        if (!orders) {
            console.log(`ruleName [${origin}] is not find order!, now ramdom get unused order!`)
            orders = this.getUnusedOrder();
        }
        console.log(`ruleName [${origin}] get order: ${JSON.stringify(orders)}`)
     
        orders.status = OrderStatus.USED;
        this._useOrderCnt++;
        return orders;
    }

    getNeedCards() {
        let op = OrderPoolMgr.getInstance();

        let usedOrder = op.getUsedOrder();
        let needCards: number[] = [];
        for (let i = 0; i < usedOrder.length; i++) {
            let order = usedOrder[i];
            needCards.push(...order.getNeedCardUids());
        }
        return needCards;
    }
}